package service

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"github.com/unknwon/com"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
	"zimuzu_cvn_web_api/model"
	"zimuzu_cvn_web_api/pkg/e"
	"zimuzu_cvn_web_api/pkg/errno"

	"zimuzu_cvn_web_api/pkg/drive/redis"
)

const AccessKey = "Ffb1PNow3k_Y7gla"
const AccessSecret = "e6uWWLEqdw3vIIoz53F3fRCRmE4MWU"

func YxSign(CanonicalQueryString string) (Sign string) {

	// 5、StringToSign
	PreStr, _ := com.UrlDecode("/")
	StringToSign := "GET&" + PreStr + "&" + CanonicalQueryString

	// 6、计算HMAC值
	HmacKey := AccessSecret + "&"
	h := hmac.New(sha1.New, []byte(HmacKey))
	h.Write([]byte(StringToSign))

	HMacSha1Str := hex.EncodeToString(h.Sum(nil))

	// 7、对HMAC值进行Base64
	Signature := base64.StdEncoding.EncodeToString([]byte(HMacSha1Str))

	// 8、拼接url形成 FinalQueryString
	FinalQueryString := CanonicalQueryString + "&signature=" + Signature

	return FinalQueryString
}

// 获取网心流量数据数据
func GetYxFlowData(StartTime, EndTime string, Page, PageSize int) (response model.YXFlowsResponse, err error) {

	// 2、按照参数名字字典排序
	v := url.Values{}
	v.Add("access_key", AccessKey)
	v.Add("action", "DescribeNodeTotalFlowByHour")
	//v.Add("NodeList", "[\"STLX3_4842953_00:00:0c:00:01:51\"]")
	//v.Add("NodeList", "[\"STLY2_6367630_151901000110\"]")
	v.Add("StartTime", StartTime)
	v.Add("EndTime", EndTime)
	v.Add("PageSize", strconv.Itoa(PageSize))
	v.Add("Page", strconv.Itoa(Page))
	v.Add("signature_method", "hmac-sha1")
	v.Add("signature_version", "1.0")
	v.Add("timestamp", time.Now().Format("2006-01-02T15:04:05Z"))
	v.Add("version", "2.0")

	// 4、CanonicalQueryString
	CanonicalQueryString := v.Encode()

	Url := YxSign(CanonicalQueryString)
	// 生成url
	client := &http.Client{}
	UrlStr := "http://api.xycdn.com/v2?" + Url
	e.Log("info", UrlStr)
	// 提交请求
	request, err := http.NewRequest("GET", UrlStr, nil)
	if err != nil {
		return response, err
	}

	resp, err := client.Do(request)
	if err != nil {
		return response, err
	}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	err = json.Unmarshal(body, &response)
	if err != nil {
		e.Log("err", "Http 请求解析数据失败111", err.Error())
		return response, err
	}
	return
}

// 获取网心流量数据数据
func GetYxFlowDataByNode(NodeStr, StartTime, EndTime string, Page, PageSize int) (response model.YXFlowsResponse, UrlStr string, err error) {

	// 2、按照参数名字字典排序
	v := url.Values{}
	v.Add("access_key", AccessKey)
	v.Add("action", "DescribeNodeTotalFlowByHour")
	v.Add("NodeList", "[\""+NodeStr+"\"]")
	v.Add("StartTime", StartTime)
	v.Add("EndTime", EndTime)
	v.Add("PageSize", strconv.Itoa(PageSize))
	v.Add("Page", strconv.Itoa(Page))
	v.Add("signature_method", "hmac-sha1")
	v.Add("signature_version", "1.0")
	v.Add("timestamp", time.Now().Format("2006-01-02T15:04:05Z"))
	v.Add("version", "2.0")

	// 4、CanonicalQueryString
	CanonicalQueryString := v.Encode()

	Url := YxSign(CanonicalQueryString)
	// 生成url
	client := &http.Client{}
	UrlStr = "http://api.xycdn.com/v2?" + Url
	// 提交请求
	request, err := http.NewRequest("GET", UrlStr, nil)
	if err != nil {
		return response, UrlStr, err
	}

	resp, err := client.Do(request)
	if err != nil {
		return response, UrlStr, err
	}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	err = json.Unmarshal(body, &response)
	if err != nil {
		e.Log("err", "Http 请求解析数据失败111", err.Error())
		return response, UrlStr, err
	}
	return
}

// 查询接点信息接口
func GetNodeInfoData(StartTime, EndTime string, Page, PageSize int) (response model.YXInfoResponse, err error) {

	// 2、按照参数名字字典排序
	v := url.Values{}
	v.Add("access_key", AccessKey)
	v.Add("action", "DescribeNodeInfoData")
	v.Add("StartTime", StartTime)
	v.Add("EndTime", EndTime)
	v.Add("PageSize", strconv.Itoa(PageSize))
	v.Add("Page", strconv.Itoa(Page))
	v.Add("signature_method", "hmac-sha1")
	v.Add("signature_version", "1.0")
	v.Add("timestamp", time.Now().Format("2006-01-02T15:04:05Z"))
	v.Add("version", "2.0")

	// 4、CanonicalQueryString
	CanonicalQueryString := v.Encode()

	Url := YxSign(CanonicalQueryString)
	// 生成url
	client := &http.Client{}
	UrlStr := "http://api.xycdn.com/v2?" + Url
	e.Log("info", UrlStr)
	// 提交请求
	request, err := http.NewRequest("GET", UrlStr, nil)
	if err != nil {
		return response, err
	}

	resp, err := client.Do(request)
	if err != nil {
		return response, err
	}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(body, &response)
	if err != nil {
		e.Log("err", "Http 请求解析数据失败134", err.Error())
		return response, err
	}
	return response, nil
}

// 从缓存获取到结点数据
func GetMgNodeInfoByCache(NodeStr string) (NodeInfo model.MgNodeResponse, Way int, err error) {

	NodeIdStr := strings.Split(NodeStr, "_")
	if len(NodeIdStr) != 3 {
		return NodeInfo, 0, errno.RecordError
	}

	var Uid int64
	var Keyword string
	switch NodeIdStr[0] {
	case "STLY2": // 路由器
		Way = 3
		Uid, _ = strconv.ParseInt(NodeIdStr[1], 10, 64)
		Keyword = NodeIdStr[2]
		break
	case "STLX3": // linux
		Way = 2
		Uid, _ = strconv.ParseInt(NodeIdStr[1], 10, 64)
		Keyword = NodeIdStr[2]
		break
	case "1": // PC端
		Way = 1
		Uid, _ = strconv.ParseInt(NodeIdStr[1], 10, 64)
		Keyword = NodeIdStr[2]
		break
	case "STLM2": // 二代 路由器
		Way = 3
		Uid, _ = strconv.ParseInt(NodeIdStr[1], 10, 64)
		Keyword = NodeIdStr[2]
		break
	default:
		Way = 0
		break
	}

	cacheKey := e.WxNodeInfoForCache + NodeStr
	if redis.Exists(cacheKey) {
		reData, _ := redis.Get(cacheKey)
		err = json.Unmarshal([]byte(reData), &NodeInfo)
		if err != nil {
			redis.UnDelete(cacheKey)
		}
		return NodeInfo, Way, nil
	}

	if Uid <= 0 {
		e.Log("info", "[node] = ", NodeStr, ", ignore")
		return NodeInfo, Way, errno.RecordError
	}

	// 获取指定结点，判断结点是否存在
	NodeInfo, err = model.GetMgNodeInfoByUidS(Uid, Keyword, Way)
	if err != nil {
		return NodeInfo, Way, err
	}
	jsonData, _ := json.Marshal(NodeInfo)
	redis.SetUnRe(cacheKey, string(jsonData), e.TimeFormatHour)

	return NodeInfo, Way, nil
}

// 处理网心接口返回一页的数据
func doneUpdateNodeFlow(taskNum int, res model.YXFlowsResponse) {
	FlowData := res.Result.FlowData
	var sqlListStr []string
	for _, k := range FlowData {
		sqlStr := UpdateMgNodeFlow(k.Node, k.Time, k.Value/1024)
		if sqlStr != "" {
			sqlListStr = append(sqlListStr, sqlStr)
		}
	}
	// sql数组准备好了
	err := model.BatchUpdateNodeFlowSql(sqlListStr)
	if err != nil {
		e.Log("err", "批量队列更新失败:", err)
		return
	}
	e.Log("info", "【第", taskNum, "页数据】已经处理完成")
	return
}

// 更新网心接口返回一条数据sql
func UpdateMgNodeFlow(NodeStr, TimeStr string, Flow float64) (sqlStr string) {
	// 先看数据库是否更新过
	NodeInfo, Way, err := GetMgNodeInfoByCache(NodeStr)
	if err != nil {
		e.Log("err", err)
		return
	}
	TimeInt64 := e.StrToTime(TimeStr)
	err = CheckNodeFlowSetStatus(NodeInfo.NodeId, TimeInt64, Way)
	if err == nil {
		return
	}
	sqlStr = model.GetUpdateNodeFlowSql(NodeInfo.NodeId, Flow, Way, 1, TimeInt64)
	return
}

// 从缓存取是否更新过该节点的数据信息
func CheckNodeFlowSetStatus(NodeId, TimeInt64 int64, Way int) (err error) {
	cacheKey := e.WxNodeInfoForCache + "hour:" + strconv.FormatInt(NodeId, 10) + ":" + strconv.FormatInt(TimeInt64, 10)
	if redis.Exists(cacheKey) {
		return nil
	}
	err = model.CheckNodeFlowUpdateByTime(NodeId, TimeInt64, Way)
	if err == nil {
		redis.SetUnRe(cacheKey, 1, e.TimeFormatDay)
		return nil
	}
	return errno.RecordError
}
